/*
 * Copyright 2018- The Pixie Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

syntax = "proto3";

package px.services;

option go_package = "authpb";

import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "src/api/proto/uuidpb/uuid.proto";

message AuthenticatedUserInfo {
  // User ID of the logged in user.
  px.uuidpb.UUID user_id = 1 [ (gogoproto.customname) = "UserID" ];
  // Name of the logged in user.
  string first_name = 2;
  string last_name = 3;
  // Email of the logged in user.
  string email = 4;
}

service AuthService {
  // Performs a login based on OAuth credentials and returns an opaque JWT identifier for the user.
  rpc Login(LoginRequest) returns (LoginReply);
  // Performs a signup based on OAuth credentials and returns an opaque JWT identifier for the user.
  rpc Signup(SignupRequest) returns (SignupReply);
  // Takes an opaque identifier (from above) and produces a token with user details.
  rpc GetAugmentedToken(GetAugmentedAuthTokenRequest) returns (GetAugmentedAuthTokenResponse);
  // Takes in a valid token, updates the claims with new data, then returns a new token.
  rpc RefetchToken(RefetchTokenRequest) returns (RefetchTokenResponse);
  // Takes an API key and produces a token with user details.
  rpc GetAugmentedTokenForAPIKey(GetAugmentedTokenForAPIKeyRequest)
      returns (GetAugmentedTokenForAPIKeyResponse);
  // Create a new account for the user's org and return an invite link.
  rpc InviteUser(InviteUserRequest) returns (InviteUserResponse);
  // Create a new org, create a new user, then return an invite link for that user.
  rpc CreateOrgAndInviteUser(CreateOrgAndInviteUserRequest)
      returns (CreateOrgAndInviteUserResponse);
  // Gets a short-lived token that can be used with an auth connector.
  rpc GetAuthConnectorToken(GetAuthConnectorTokenRequest) returns (GetAuthConnectorTokenResponse);
}

message LoginRequest {
  // The OAuth access token.
  string access_token = 1;
  // Automatically create the user if they don't exist.
  bool create_user_if_not_exists = 3;
  // The token containing information about which org the user was invited to join.
  // Must contain info about the org the user is invited to join and be valid for that org.
  string invite_token = 6;
  // Reserved after support accounts were removed.
  reserved 4, 5;
}

message LoginReply {
  // The opaque access token generated by our system. This is a JWT claim
  // that is used to identify the user. This token can be treated as the refresh token
  // and should not be sent to the browser or other insecure clients.
  string token = 1;
  // When this login expires.
  int64 expires_at = 2;
  // True if a new user was created while processing the LoginRequest. This is only possible if
  // create_user_if_not_exists is set in the LoginRequest.
  bool user_created = 3;
  // Information about the logged in user.
  AuthenticatedUserInfo user_info = 5;
  message OrgInfo {
    string org_id = 1 [ (gogoproto.customname) = "OrgID" ];
    string org_name = 2;
  }
  OrgInfo org_info = 6;
  // The service that provided the identity for this login.
  string identity_provider = 7;

  reserved 4;
}

message SignupRequest {
  // The OAuth access token.
  string access_token = 1;

  // The token containing information about which org the user was invited to join.
  // Must contain info about the org the user is invited to join and be valid for that org.
  string invite_token = 4;
  reserved 2, 3;
}

message SignupReply {
  // The opaque access token generated by our system. This is a JWT claim
  // that is used to identify the user. This token can be treated as the refresh token
  // and should not be sent to the browser or other insecure clients.
  string token = 1;
  // When this login expires.
  int64 expires_at = 2;
  // True if a new org was created while processing the SignupRequest.
  bool org_created = 3;
  // Information about the logged in user.
  AuthenticatedUserInfo user_info = 5;
  // Org ID of the user's org.
  px.uuidpb.UUID org_id = 6 [ (gogoproto.customname) = "OrgID" ];
  // Org name of the user's org.
  string org_name = 7;
  // The service that provided the identity for this signup.
  string identity_provider = 8;

  reserved 4;
}

message GetAugmentedAuthTokenRequest {
  // The signed token identifying the user.
  string token = 1;
}

message GetAugmentedAuthTokenResponse {
  // The signed token augmented with user information. This can contain additional information about
  // the user such as permissions, etc. This allows us to keep the initial token small.
  // This token will have a short lifetime of ~30 mins.
  string token = 1;
  // When this login expires.
  int64 expires_at = 2;
}

message RefetchTokenRequest {
  // The signed token that the user already has. Must be valid, with the exception of matching org
  // to work.
  string token = 1;
}

message RefetchTokenResponse {
  // The signed token matches the latest state in the database.
  string token = 1;
  // When this token expires.
  int64 expires_at = 2;
}

message GetAugmentedTokenForAPIKeyRequest {
  // An API Key that can be linked to a particular user/org.
  string api_key = 1 [ (gogoproto.customname) = "APIKey" ];
}

message GetAugmentedTokenForAPIKeyResponse {
  // The signed token augmented with user information. This can contain additional information about
  // the user such as permissions, etc. This allows us to keep the initial token small.
  // This token will have a short lifetime of ~30 mins.
  string token = 1;
  // When this login expires.
  int64 expires_at = 2;
}

message InviteUserRequest {
  string email = 1;
  string first_name = 2;
  string last_name = 3;

  // The ID of the organization to create the user for.
  px.uuidpb.UUID org_id = 4 [ (gogoproto.customname) = "OrgID" ];
}

message InviteUserResponse {
  string invite_link = 1;
}

message CreateOrgAndInviteUserRequest {
  message Org {
    string org_name = 1;
    string domain_name = 2;
  }
  message User {
    string first_name = 2;
    string last_name = 3;
    string email = 4;

    reserved 1;
  }
  Org org = 1;
  User user = 2;
}

message CreateOrgAndInviteUserResponse {
  string invite_link = 1;
}

message GetAuthConnectorTokenRequest {
  // ClusterName is the name of the cluster that can be used with the auth connector. This will be
  // encoded in the returned JWT. This can be modified by the user, so consumers should take care to
  // validate this is a real cluster which the user has access to.
  string cluster_name = 1;
}

message GetAuthConnectorTokenResponse {
  // A short-lived access token that can be used to access the Pixie API on behalf of a user.
  string token = 1;
  // When this token expires.
  int64 expires_at = 2;
}

//
// API Key Service
//

// The service that handles API keys.
service APIKeyService {
  // Create a new API key.
  rpc Create(CreateAPIKeyRequest) returns (APIKey);
  // List all keys for the user/org.
  rpc List(ListAPIKeyRequest) returns (ListAPIKeyResponse);
  // Get the key specified by ID.
  rpc Get(GetAPIKeyRequest) returns (GetAPIKeyResponse);
  // Delete the Key specified by ID.
  rpc Delete(uuidpb.UUID) returns (google.protobuf.Empty);
  // Lookup the API key information by the key value.
  rpc LookupAPIKey(LookupAPIKeyRequest) returns (LookupAPIKeyResponse);
}

// A key that can be used to access the Pixie API. This is value of the key
// is added to the PIXIE-API-KEY requests.
message APIKey {
  // They ID of the key.
  uuidpb.UUID id = 1 [ (gogoproto.customname) = "ID" ];
  // The value of the key.
  string key = 2;
  google.protobuf.Timestamp created_at = 3;
  // Description for the key.
  string desc = 4;

  uuidpb.UUID org_id = 5 [ (gogoproto.customname) = "OrgID" ];
  uuidpb.UUID user_id = 6 [ (gogoproto.customname) = "UserID" ];
}

// The metadata associated with the key, everything except the actual key.
message APIKeyMetadata {
  // They ID of the key.
  uuidpb.UUID id = 1 [ (gogoproto.customname) = "ID" ];
  google.protobuf.Timestamp created_at = 3;
  // Description for the key.
  string desc = 4;

  uuidpb.UUID org_id = 5 [ (gogoproto.customname) = "OrgID" ];
  uuidpb.UUID user_id = 6 [ (gogoproto.customname) = "UserID" ];

  // Reserves the key field which was used by the original APIKey proto.
  reserved 2;
}

// Create a API key.
message CreateAPIKeyRequest {
  // Description for the key.
  string desc = 1;
}

message ListAPIKeyRequest {
  // Empty message on purpose so we can extend with attributes easily if needed.
}

message ListAPIKeyResponse {
  repeated APIKeyMetadata keys = 1;
}

message GetAPIKeyRequest {
  uuidpb.UUID id = 1 [ (gogoproto.customname) = "ID" ];
}

message GetAPIKeyResponse {
  APIKey key = 1;
}

message LookupAPIKeyRequest {
  string key = 1;
}

message LookupAPIKeyResponse {
  APIKey key = 1;
}
